

char compare_and_swap(int *ptr, int old, int new) {
    unsigned char ret;
    // Note that sete sets a ’byte’ not the word
    __asm__ __volatile__ (
                          " lock\n"
                          " cmpxchgl %2,%1\n"
                          " sete %0\n"
                          : "=q" (ret), "=m" (*ptr)
                          : "r" (new), "m" (*ptr), "a" (old)
                          : "memory");
    return ret;
}

#include <pthread.h>
__thread char mlogbuf[5120];

#include <stdarg.h>
#include <stdio.h>

typedef struct stringv {
    char* str;
    int len;
    int islit;
}stringv;
typedef struct arrayv {
    int element_size;
    char* data;
    int len;
    int cap;
} arrayv;

typedef struct variantv {
    void* ptr;
    int typ;
} variantv;

int mlog_logf2(stringv* sret, stringv* file, stringv* line, arrayv* argv) {
    char* lbuf = mlogbuf;
    int pos = 0;
    int addn = 0;

    int argc = argv->len;
    //printf("argc %d\n", argc);

    stringv* sp;
    arrayv* ap;
    variantv* vp;

    // file/line
    //file->str[file->len] = '\0';
    char* bfile = strrchr(file->str, '/');
    memcpy(lbuf+pos, bfile+1, strlen(bfile)-1);
    pos += strlen(bfile)-1;
    lbuf[pos++] = ':';
    memcpy(lbuf+pos, line->str, line->len);
    pos += line->len;
    lbuf[pos++] = ' ';

    // user args
    for (int i = 0; i < argc; i++) {
        vp = argv->data + i * argv->element_size;
        // printf("i%d typ%d ptr%p\n", i, vp->typ, vp->ptr);

        variantv* arg = vp;
        switch(arg->typ) {
            // case 16: return _STR("Any(%.*s\000)", 2, bool_str(*(bool*)x._bool));
            // case 7: return _STR("Any(%.*s\000)", 2, int_str(*(int*)x._int));
        case 7:
            addn = sprintf(lbuf+pos, "%d", *(int*)(arg->ptr));
            pos += addn;
            break;
            // case 9: return _STR("Any(%.*s\000)", 2, byte_str(*(byte*)x._byte));
            // case 6: return _STR("Any(%.*s\000)", 2, i16_str(*(i16*)x._i16));
            // case 10: return _STR("Any(%.*s\000)", 2, u16_str(*(u16*)x._u16));
            // case 11: return _STR("Any(%.*s\000)", 2, u32_str(*(u32*)x._u32));
            // case 8: return _STR("Any(%.*s\000)", 2, i64_str(*(i64*)x._i64));
        case 8:
            addn = sprintf(lbuf+pos, "%ld", *(int64_t*)(arg->ptr));
            pos += addn;
            break;
            // case 12: return _STR("Any(%.*s\000)", 2, u64_str(*(u64*)x._u64));
        case 12:
            addn = sprintf(lbuf+pos, "%ud", *(uint64_t*)(arg->ptr));
            pos += addn;
            break;
            // case 13: return _STR("Any(%.*s\000)", 2, f32_str(*(f32*)x._f32));
            // case 14: return _STR("Any(%.*s\000)", 2, f64_str(*(f64*)x._f64));
        case 14: // double
            addn = sprintf(lbuf+pos, "%f", *(double*)(arg->ptr));
            pos += addn;
            break;
            // case 18: return _STR("Any('%.*s\000')", 2, string_str(*(string*)x._string));
        case 18:
            sp = (stringv*)(arg->ptr);
            memcpy(lbuf+pos, sp->str, sp->len);
            pos += sp->len;
            break;
            // case 30: return _STR("Any(%.*s\000)", 2, array_int_str(*(array_int*)x._array_int));
            // case 54: return _STR("Any(%.*s\000)", 2, array_i64_str(*(array_i64*)x._array_i64));
            // case 55: return _STR("Any(%.*s\000)", 2, array_f64_str(*(array_f64*)x._array_f64));
            // case 32: return _STR("Any(%.*s\000)", 2, array_voidptr_str(*(array_voidptr*)x._array_voidptr));
            // case 41: return _STR("Any(%.*s\000)", 2, array_byteptr_str(*(array_byteptr*)x._array_byteptr));
            // case 39: return _STR("Any(%.*s\000)", 2, array_charptr_str(*(array_charptr*)x._array_charptr));
            // case 28: return _STR("Any(%.*s\000)", 2, array_string_str(*(array_string*)x._array_string));
        case 28: // array_string
            ap = (arrayv*)(arg->ptr);
            //printf("%d %d\n", ap->len, ap->element_size);
            lbuf[pos++] = '[';
            for (int j = 0; j < ap->len; j++) {
                sp = ap->data + j * ap->element_size;
                //printf("j%d, %d %s\n", j, p->len, p->str);
                memcpy(lbuf+pos, sp->str, sp->len);
                pos += sp->len;
                lbuf[pos++] = ',';
                lbuf[pos++] = ' ';
            }
            lbuf[pos++] = ']';
            break;
            // case 57: return _STR("Any(%.*s\000)", 2, array_Any_str(*(array_Any*)x._array_Any));
            // case 58: return _STR("Any(%.*s\000)", 2, map_string_string_str(*(map_string_string*)x._map_string_string));
            // case 59: return _STR("Any(%.*s\000)", 2, map_voidptr_string_str(*(map_voidptr_string*)x._map_voidptr_string));
            // case 60: return _STR("Any(%.*s\000)", 2, map_int_string_str(*(map_int_string*)x._map_int_string));
            // case 24: return _STR("Any(%.*s\000)", 2, size_t_str(*(size_t*)x._size_t));
            // case 61: return _STR("Any(%.*s\000)", 2, array_size_t_str(*(array_size_t*)x._array_size_t));
            // case 2: return _STR("Any(%.*s\000)", 2, voidptr_str(*(voidptr*)x._voidptr));
        case 2:
            addn = sprintf(lbuf+pos, "%p", arg->ptr);
            pos += addn;
            break;
            // case 3: return _STR("Any(%.*s\000)", 2, byteptr_str(*(byteptr*)x._byteptr));
            // case 4: return _STR("Any(%.*s\000)", 2, charptr_str(*(charptr*)x._charptr));
            // default: return _SLIT("unknown sum type value");
        default:
            addn = sprintf(lbuf+pos, "unty%d", arg->typ);
            pos += addn;
            break;
        }
        if (i < argc-1) {
            lbuf[pos++] = ' ';
        }
    }

    lbuf[pos] = '\0';
    sret->str = lbuf;
    sret->len = pos;
    sret->islit = 1; // not let v free this

    return pos;
}

int mylogf(stringv* sret, stringv* file, stringv* line, int num, ...) {
    char* lbuf = mlogbuf;
    int pos = 0;
    int addn = 0;
    stringv* p;
    arrayv* ap;
    va_list alst;

    va_start(alst, num);
    for (int i = 0; i < num; i++) {
        variantv* arg = va_arg(alst, variantv*);
        // printf("i%d typ%d ptr%p\n", i, arg->typ, arg->ptr);
        switch (arg->typ) {
        case 7: // int
            addn = sprintf(lbuf+pos, "%d", *(int*)(arg->ptr));
            pos += addn;
            break;
        case 18: // string
            p = (stringv*)(arg->ptr);
            memcpy(lbuf+pos, p->str, p->len);
            pos += p->len;
            break;
        case 14: // double
            addn = sprintf(lbuf+pos, "%f", *(double*)(arg->ptr));
            pos += addn;
            break;
        case 28: // array_string
            ap = (arrayv*)(arg->ptr);
            //printf("%d %d\n", ap->len, ap->element_size);
            lbuf[pos++] = '[';
            for (int j = 0; j < ap->len; j++) {
                p = ap->data + j * ap->element_size;
                //printf("j%d, %d %s\n", j, p->len, p->str);
                memcpy(lbuf+pos, p->str, p->len);
                pos += p->len;
                lbuf[pos++] = ',';
                lbuf[pos++] = ' ';
            }
            lbuf[pos++] = ']';
            break;
        default:
            addn = sprintf(lbuf+pos, "unty%d", arg->typ);
            pos += addn;
            break;
        }
        if (i < num-1) {
            lbuf[pos++] = ' ';
        }
        lbuf[pos] = '\0';
    }
    va_end(alst);

    //printf("%d %s\n", pos, lbuf);
    sret->str = lbuf;
    sret->len = pos;
    sret->islit = 1; // not let v free this
    return 0;
}

